﻿#region Copyright ©2008-2010, Technische Universitaet Muenchen
// ====================================================================================================
//
// Last Changed by       $Author: then $
// Last Changed Date     $LastChangedDate: 2009-06-15 08:45:45 +0200 (Mon, 15 Jun 2009) $
// Last Changed Revision $Rev: 194 $
//
// ====================================================================================================
#endregion

using System;
using System.Collections.Generic;
using System.Reflection;

namespace Tum.CollabXT.Wizard
{
    /// <summary>
    /// Information about a process provider.
    /// </summary>
    public class ProviderInfo : IEquatable<ProviderInfo>
    {
        /// <summary>
        /// Name of the provider.
        /// </summary>
        public string Name
        {
            get; protected set;
        }

        /// <summary>
        /// Description of the provider.
        /// </summary>
        public string Description
        {
            get; protected set;
        }

        /// <summary>
        /// The provider's author.
        /// </summary>
        public string Author
        {
            get; protected set;
        }

        /// <summary>
        /// Path of the provider assembly.
        /// </summary>
        public string AssemblyPath
        {
            get; protected set;
        }

        /// <summary>
        /// Type implementing the provider interface.
        /// </summary>
        public Type InterfaceType
        {
            get; protected set;
        }


        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="assemblyPath">Path of the provider assembly.</param>
        /// <param name="interfaceType">Provder interface implementing type.</param>
        public ProviderInfo(string assemblyPath, Type interfaceType)
        {
            AssemblyPath = assemblyPath;

            if (interfaceType == null)
                throw new CxtWizardException("Interface type must not be null");
            InterfaceType = interfaceType;

            #region Load name, description and author from assembly or set default values
            MethodInfo getNameMethod = interfaceType.GetMethod("GetProviderName");
            if (getNameMethod != null)
            {
                if (getNameMethod.IsStatic && getNameMethod.IsPublic)
                {
                    try
                    {
                        Name = getNameMethod.Invoke(null, null) as string;
                    }
                    catch (Exception) {}
                }
            }

            
            MethodInfo getDescMethod = interfaceType.GetMethod("GetProviderDescription");
            if (getDescMethod != null)
            {
                if (getDescMethod.IsStatic && getDescMethod.IsPublic)
                {
                    try
                    {
                        Description = getDescMethod.Invoke(null, null) as string;
                    }
                    catch (Exception) { }
                }
            }
            

            MethodInfo getAuthorMethod = interfaceType.GetMethod("GetProviderAuthor");
            if (getAuthorMethod != null)
            {
                if (getAuthorMethod.IsStatic && getAuthorMethod.IsPublic)
                {
                    try
                    {
                        Author = getAuthorMethod.Invoke(null, null) as string;
                    }
                    catch (Exception) { }
                }
            }

            if (Name == null)
            {
                Name = AssemblyPath.Substring(Math.Max(AssemblyPath.LastIndexOf('/'), AssemblyPath.LastIndexOf('\\')) + 1);
                Name = Name.Substring(0, Name.LastIndexOf('.'));
            }
            if (Description == null)
                Description = string.Empty;
            if (Author == null)
                Author = string.Empty;
            #endregion
        }

        /// <summary>
        /// Checks if two providers are equal.
        /// </summary>
        /// <param name="other">The provider the current one is to be checked against.</param>
        /// <returns>True, if the two providers are equal, false if not.</returns>
        public bool Equals(ProviderInfo other)
        {
            if (other == null)
                return false;
            return this.AssemblyPath.Equals(other.AssemblyPath, StringComparison.OrdinalIgnoreCase) && this.InterfaceType.Equals(other.InterfaceType);
        }

        /// <summary>
        /// Checks, if a provider assembly is already in a provider list.
        /// </summary>
        /// <param name="list">The provider list to be checked.</param>
        /// <param name="assemblyPath">Assembly path to be searched for.</param>
        /// <param name="interfaceType">Provider implementing type within the assembly.</param>
        /// <returns>True, if this provider is already in the list, false if not.</returns>
        public static bool AlreadyInList(ICollection<ProviderInfo> list, string assemblyPath, Type interfaceType)
        {
            foreach (var cur in list)
            {
                if (cur.AssemblyPath.Equals(assemblyPath, StringComparison.OrdinalIgnoreCase) && 
                    cur.InterfaceType.Equals(interfaceType))
                    return true;
            }
            return false;
        }
    }

    /// <summary>
    /// Process provider information class.
    /// </summary>
    public class ProcessProviderInfo : ProviderInfo
    {
        /// <summary>
        /// Current instance of this process provider.
        /// </summary>
        public IProcessProvider Instance
        {
            get
            {
                if (_Instance == null)
                    _Instance = CreateProvider();
                return _Instance;
            }
        }
        IProcessProvider _Instance;


        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="assemblyPath">Path of the provider assembly.</param>
        /// <param name="interfaceType">Provder interface implementing type.</param>
        public ProcessProviderInfo(string assemblyPath, Type processProviderImplementingType)
            : base(assemblyPath, processProviderImplementingType)
        { }

        /// <summary>
        /// Creates an instance of this provider.
        /// </summary>
        IProcessProvider CreateProvider()
        {
            try
            {
                return Activator.CreateInstance(InterfaceType) as IProcessProvider;
            }
            catch { return null;  }
        }
    }

    /// <summary>
    /// Tool provider information class.
    /// </summary>
    public class ToolProviderInfo : ProviderInfo
    {
        /// <summary>
        /// Current instance of this tool provider.
        /// </summary>
        public IToolProvider Instance
        {
            get
            {
                if (_Instance == null)
                    _Instance = CreateProvider();
                return _Instance;
            }
        }
        IToolProvider _Instance;


        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="assemblyPath">Path of the provider assembly.</param>
        /// <param name="interfaceType">Provder interface implementing type.</param>
        /// <param name="assemblyPath"></param>
        /// <param name="toolProviderImplementingType"></param>
        public ToolProviderInfo(string assemblyPath, Type toolProviderImplementingType)
            : base(assemblyPath, toolProviderImplementingType)
        { }

        /// <summary>
        /// Creates an instance of this provider.
        /// </summary>
        IToolProvider CreateProvider()
        {
            try
            {
                return Activator.CreateInstance(InterfaceType) as IToolProvider;
            }
            catch { return null;  }
        }

        /// <summary>
        /// Initialization state of this tool provider.
        /// True if already initialized, false if not.
        /// </summary>
        public bool Initialized;
    }
}
